﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace Transportr
{
    public class Settings
    {
        public enum MetaType { Numeric, Text, Choice }

        [Serializable]
        public class MetaItem
        {
            [XmlElement]
            public string name;
            [XmlElement]
            public TypeCode type;
            [XmlElement]
            public MetaType metaType;
            [XmlElement]
            public List<object> defaultValues;
            [XmlElement]
            public List<object> values;
            [XmlElement]
            public string[] description;

            public MetaItem()
            {
                this.defaultValues = new List<object>();
                this.values = new List<object>();
            }
        }

        public class MetaGroup
        {
            [XmlElement]
            public string groupName;
            [XmlElement]
            public List<MetaItem> items;
            [XmlElement]
            public List<MetaGroup> childGroups;

            public MetaGroup()
            {
                this.items = new List<MetaItem>();
                this.childGroups = new List<MetaGroup>();
            }
        }

        [Serializable]
        [XmlRoot]
        public class SettingsStore
        {
            [XmlElement]
            public List<MetaGroup> metaData;

            public SettingsStore()
            {
                this.metaData = new List<MetaGroup>();
            }
        }

        public SettingsStore Store { get; set; }

        private string Path;
        public bool Valid { get; private set; }

        public Settings(string FilePath)
        {
            this.Path = FilePath;
            this.Store = new SettingsStore();
            this.Load();
        }

        public void Load()
        {
            if (File.Exists(Path))
            {
                try
                {
                    using (FileStream fs = new FileStream(Path, FileMode.Open))
                    {
                        Store = (SettingsStore)(new XmlSerializer(typeof(SettingsStore)).Deserialize(fs));
                    }
                    this.Valid = true;
                }
                catch (InvalidOperationException x)
                {
                    this.Valid = false;
                    System.Diagnostics.Debug.WriteLine(x.Message);
                }
            }
            else
            {
                this.Valid = false;
            }
        }

        public void Save()
        {
            try
            {
                using (FileStream fs = new FileStream(Path, FileMode.Create))
                {
                    new XmlSerializer(typeof(SettingsStore)).Serialize(fs, Store);
                }
            }
            catch (Exception x)
            {
                System.Windows.Forms.MessageBox.Show(x.Message);
            }
        }

        private MetaGroup GetGroup(string name)
        {
            foreach (MetaGroup g in Store.metaData)
                if (g.groupName == name)
                    return g;
            return null;
        }

        private MetaItem GetItem(string _name)
        {
            foreach (MetaGroup g in Store.metaData)
                foreach (MetaItem i in g.items)
                    if (i.name == _name) return i;
            return null;
        }
        // TODO: UGLY AS HELL! Convert these into Lambda expressions
        public void InitDefault(string _name, string _groupName, TypeCode _type, MetaType _metaType, List<object> _values, string[] _description)
        {
            MetaItem item = this.GetItem(_name);
            if (item != null)
            {
                item.defaultValues = _values;
                item.description = _description;
            }
            else
            {
                MetaGroup g = this.GetGroup(_groupName);
                if (g != null)
                    g.items.Add(new MetaItem()
                    {
                        name = _name,
                        type = _type,
                        metaType = _metaType,
                        values = _values,
                        description = _description
                    });
                else
                {
                    Store.metaData.Add(new MetaGroup()
                    {
                        groupName = _groupName
                    });
                    g = this.GetGroup(_groupName);
                    g.items.Add(new MetaItem()
                    {
                        name = _name,
                        type = _type,
                        metaType = _metaType,
                        values = _values,
                        description = _description
                    });
                }
            }
        }

        public object Get(string name)
        {
            // try to find the value if the parameter
            foreach (MetaGroup g in Store.metaData)
            {
                foreach (MetaItem i in g.items)
                {
                    // TBD: throw exception if list type...
                    if (i.name == name)
                    {
                        if (i.values != null)
                            return i.values[0];
                        else return i.defaultValues[0];
                    }
                }
            }
            return null;
        }

        public bool Set(string name, object value)
        {
            foreach (MetaGroup g in Store.metaData)
            {
                foreach (MetaItem i in g.items)
                {
                    // TBD: throw exception if list type...
                    if (i.name == name)
                    {
                        i.values[0] = value;
                    }
                }
            }
            return true;
        }


        public List<object> GetList(string name)
        {
            return null;
        }

        public bool SetList(string name, List<object> value)
        {
            return false;
        }
    }
}
